/********************************Copyright (c)**********************************\
**
**                   (c) Copyright 2019, Main, China, Mrtutu.
**                           All Rights Reserved
**
**                                By Mrtutu
**                           Blog: www.mrtutu.cn
**
**----------------------------------文件信息------------------------------------
** @flie    : SLE4442.c
** @auther  : Mrtutu
** @date    : 2019-10-30
** @describe:
**
**----------------------------------版本信息------------------------------------
** 版本代号: V0.1
** 版本说明: 初始版本
**
**------------------------------------------------------------------------------
\********************************End of Head************************************/

#include "SLE4442.h"
#include "Debug.H"
#include "GPIO.H"
#include <stdio.h>

//unsigned char INIT_PASSWD[3] = {0xFF, 0xFF, 0xFF};
//unsigned char NEW_PASSWD[3] = {0x66, 0x66, 0x66};
//unsigned char WD_BUF[6] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};


sbit SLE_DATA = P1^6;
sbit SLE_CLK  = P1^5;
sbit SLE_RST  = P1^4;

// 初始化
void SLE4442_Init(void)
{
    SLE_SDA_OUT();  // DAT设置为推挽输出
    Port1Cfg(1, 5); // CLK 推挽输出
    Port1Cfg(1, 4); // RST 推挽输出

//    SLE_DATA = 1;
//    SLE_CLK  = 1;
//    SLE_RST  = 1;
}

// 延时函数
void SLE4442_Delay(void)
{
    UINT8 a;
    for(a = 0; a < 33; a++);
}

// 启动总线
void SLE4442_Start(void)
{
    SLE_SDA_OUT();  // SDA设置为推挽输出
    SLE_CLK  = 0;
    SLE_DATA = 1;
    SLE_CLK  = 1;
    SLE4442_Delay();
    SLE_DATA = 0;
    SLE4442_Delay();
    SLE_CLK  = 0;
    SLE4442_Delay();
}


void SLE4442_Stop(void)
{
    SLE_SDA_OUT();  // SDA设置为推挽输出
    SLE_DATA = 0;
    SLE4442_Delay();
    SLE_CLK  = 1;
    SLE4442_Delay();
    SLE_DATA = 1;	//发送起始信号
    SLE4442_Delay();
}


//复位和复位响应
//接收响应字节.
// 0 复位成功
// 1 复位失败 卡为无效卡或卡已失效
unsigned char SLE_Rst(void)
{
    unsigned char i = 0;
    unsigned char ReadBuf[4] = {0};

    //SLE_SDA_OUT();  // SDA设置为推挽输出

    SLE_DATA = 0;
    SLE_CLK  = 0;
    SLE4442_Delay();
    SLE_RST  = 1;
    SLE4442_Delay();
    SLE_CLK  = 1;
    SLE4442_Delay();
    SLE_CLK  = 0;
    SLE4442_Delay();
    SLE_RST  = 0;

    for(i = 0; i < 4; i++)
    {
        ReadBuf[i] = SLE_RD_Byte();
    }

    SLE_CLK  = 1;
    SLE4442_Delay();
    SLE_CLK  = 0;
    SLE_DATA = 1;

    SLE4442_Delay();
    return 0;
    
//    if((ReadBuf[0] == SLE4442ID1) && (ReadBuf[1] == SLE4442ID2) &&
//      (ReadBuf[2] == SLE4442ID3) && (ReadBuf[3] == SLE4442ID4))
//    {
//        return 0; //复位值正确,返回复位成功
//    }
//    else
//    {
//        return 1;			//复位值错误,返回复位失败
//    }

//     SLE_DATA = 1;
//     SLE_CLK  = 0;
//     SLE4442_Delay();
//     SLE_RST  = 1;
//     SLE4442_Delay();
//     SLE_CLK  = 1;
//     SLE4442_Delay();
//     SLE_CLK  = 0;
//     SLE4442_Delay();
//     SLE_RST  = 0;
//     SLE4442_Delay();
//     SLE_RD_Byte();
//     SLE_RD_Byte();
//     SLE_RD_Byte();
//     SLE_RD_Byte();
//     SLE_DATA = 0;
//     SLE4442_Delay();
//     return 0;
}  

//等待操作完成(内部处理模式)
//返回值:0，操作成功;其他,错误代码
unsigned char SLE_Wait(void)
{
    unsigned char i = 0;

    SLE_SDA_IN();
    SLE_DATA = 1; //51读IO前要置1
    while(i < 255)
    {
        i++;
        SLE_CLK  = 0;
        SLE4442_Delay();
        SLE_CLK  = 1;
        SLE4442_Delay();
        if(SLE_DATA)
        {
            SLE_SDA_OUT();
            return 0;    // 成功
        }
        SLE_SDA_OUT();
        return 1;  // 失败
    }

}

////得到复位响应
////buf:存储atr的指针
//void SLE_Getatr(unsigned char* buf)
//{
//    SLE_RST  = 0;
//    SLE_CLK  = 0;
//    SLE4442_Delay();
//    SLE_RST  = 1;
//    SLE4442_Delay();
//    SLE_CLK  = 1;
//    SLE4442_Delay();
//    SLE_CLK  = 0;
//    SLE4442_Delay();
//    SLE_RST  = 0;
//    buf[0] = SLE_RD_Byte();
//    buf[1] = SLE_RD_Byte();
//    buf[2] = SLE_RD_Byte();
//    buf[3] = SLE_RD_Byte();
//}

// 中止操作
void SLE_Break(void)
{
    SLE_CLK  = 0;
    SLE4442_Delay();
    SLE_CLK  = 1;
    SLE4442_Delay();
    SLE_CLK  = 0;
}


//向SLE写入一个字节
void SLE_WR_Byte(u8 x)
{
    u8 i;
    SLE_SDA_OUT();
    for(i = 0; i < 8; i++)
    {
        if(x & 0x01)SLE_DATA = 1;
        else SLE_DATA = 0;
        SLE4442_Delay();
        SLE_CLK  = 1;
        SLE4442_Delay();
        SLE_CLK  = 0;
        x >>= 1;
    }
}

//从SLE读取一个字节
u8 SLE_RD_Byte(void)
{
    u8 i, x;
    x = 0;
    SLE_SDA_IN();
    SLE_DATA = 1; //51读IO前要置1
    for(i = 0; i < 8; i++)
    {
        SLE_CLK = 0;
        SLE4442_Delay();
        SLE_CLK = 1;
        SLE4442_Delay();
        x >>= 1;
        if(SLE_DATA) x |= 0x80;
    }
    SLE_CLK = 0;
    SLE4442_Delay();
    //SLE_SDA_OUT();
    return x;
}



void SLE_WR_Cmd(u8 cmd, u8 address, u8 _data)
{
    SLE4442_Start();
    SLE_WR_Byte(cmd);
    SLE_WR_Byte(address);
    SLE_WR_Byte(_data);
    SLE4442_Stop();
}


//SLE指定地址读取指定长度的数据
//area:存储器范围
//addr:地址
//len:读取长度
//*buf:输出存放地址
void SLE_RD_Data(u8 area, u8 addr, u8 len, u8* buf)
{
    u8 i;
    //printf("Enter SLE_RD_Data \n");
    SLE_Rst();
    //printf("RST OK  \n");
    SLE_WR_Cmd(area, addr, 0);
    // printf("SLE_WR_Cmd OK \n");
    for(i = 0; i < len; i++)	//读取数据
    {
        buf[i] = SLE_RD_Byte();
    }
    //printf("WR OK \n");
//    SLE_CLK = 1;
//    SLE4442_Delay();
//    SLE_CLK = 0;
//    SLE4442_Delay();
}

//SLE指定地址开始写入指定长度的数据
//area:存储器范围
//addr:地址
//len:写入长度
//buf:数据地址
//返回值:0，操作成功;其他,错误代码
unsigned char SLE_WR_Data(u8 area, u8 addr, u8 len, u8* buf)
{
    unsigned char i = 0, sta = 0;
    SLE_Rst();
    for(i = 0; i < len; i++)
    {
        SLE_WR_Cmd(area | 0x80, addr + i, buf[i]); //发送命令 0X38/0X39/0X3C  地址+数据
        sta = SLE_Wait();
        if(sta)break;
    }
    return sta;
}


//功    能：从主存储器中读出数据块并存入ReadBuf中
//输	  入：unsigned char StarAddr --- 开始地址(0 - 255)
//		  unsigned char ByteNum  --- 要读出的字节数(1 - 256)
//		  unsigned char *RecBuf  --- 接收数据缓冲区
//输	  出: 0 --- 读成功
//		  1 --- 表示无效卡或者卡损坏
unsigned char SLE_RD_CM(unsigned char StarAddr, unsigned char ByteNum, unsigned char* RecBuf)
{
    unsigned char i = 0;

    if((StarAddr < 0) || (StarAddr > 255))
        return 1;

    if((256 - StarAddr) < ByteNum)
        return 1;

    if(SLE_Rst() == 1)return 1;

    SLE_WR_Cmd(SLE_RD_MRAM, StarAddr, 0x00); //发送读主存命令

    for(i = 0; i < ByteNum; i++)
    {
        *RecBuf = SLE_RD_Byte();
        RecBuf++;
    }
    return 0;
}


//功    能: 把存在WriteBuf中的ByteNum个字节的数据存入主存储器中
//输    入: unsigned char StarAdr   --- 开始地址(0 - 255)
//          unsigned char ByteNum   --- 要写入的字节数(1 - 256)
//	      unsigned char *WriteBuf --- 写入数据缓冲区
//输	  出: 0 --- 写成功
//		  1 --- 表示无效卡或者卡损坏
//注	  意：要校验密钥正确，才能对卡的主存储器写入数据
unsigned char SLE_WR_CM(unsigned char StarAddr, unsigned char ByteNum, unsigned char* WriteBuf)
{
    unsigned char i = 0, sta = 0;

    if((StarAddr < 0) || (StarAddr > 255))
        return 1;

    if((256 - StarAddr) < ByteNum)
        return 1;

    if(SLE_Rst() == 1)return 1;

    for(i = 0; i < ByteNum; i++)
    {
        SLE_WR_Cmd(SLE_WR_MRAM, StarAddr, *WriteBuf);	        //发送写主存储区命令
        sta = SLE_Wait();	  		                            //发送操作脉冲
        if(sta) break;			                                //超时了
        StarAddr++;								                //写入字节地址加1
        WriteBuf++;								                //写入缓冲区指针加1
    }

    printf("\r\nWD OK IN\r\n");
    return 0;
}



// 发送处理脉冲
void SLE_SendCLK(void)
{
    SLE_SDA_IN();
    SLE_DATA = 1; //51读IO前要置1
    SLE_CLK = 0;
    SLE4442_Delay();
    SLE_CLK = 1;
    SLE4442_Delay();

    do
    {
        SLE_CLK = 0;
        SLE4442_Delay();
        SLE_CLK = 1;
        SLE4442_Delay();
    }
    while(SLE_DATA == 0);
    //不断产生处理脉冲,驱动IC卡内部处理,直到IC卡将IO口拉为高电平
}


//功    能：读保护存储器,并把保护存储器的4字节的内容存在RecBuf中
//输	  入：unsigned char *RecBuf  --- 接收数据缓冲区,长度为4个字节
//输    出：0 --- 读成功
//		  1 --- 表示无效卡或者卡损坏
unsigned char SLE_RD_PM(unsigned char* RecBuf)
{
    unsigned char i = 0;
    if(SLE_Rst() == 1)return 1;
    SLE_WR_Cmd(SLE_RD_PRAM, 0x00, 0x00);
    for(i = 0; i < 32; i++)	
    {
        *RecBuf = SLE_RD_Byte();
        RecBuf++;						              //接收缓冲区指针加1
    }
    return 0;
}



//功    能：写保护数据存储器
//输	  入：unsigned char StartAdr  --- 起始地址(0 - 31)
//	        unsigned char ByteNum   --- 写入的字节数(1 - 32)
//	 	      unsigned char *WriteBuf --- 写入数据缓冲区
//输	  出：0 --- 写成功
//		  1 --- 表示无效卡或者卡损坏
//注	  意: 首先校验密钥正确，才能对卡的保护存储器写入数据，
//          其次写入的数据必须与卡中对应的数据相等才能写入
unsigned char SLE_WR_PM(unsigned char StartAdr, unsigned char ByteNum, unsigned char* WriteBuf)
{
    unsigned char i, sta = 0;

    if((StartAdr < 0) || (StartAdr > 31))
        return 1;

    if(ByteNum > (32 - StartAdr))
        return 1;
    
    if(SLE_Rst() == 1)
        return 1;
    
    for(i = 0; i < ByteNum; i++)
    {
        SLE_WR_Cmd(SLE_WR_PRAM, StartAdr, *WriteBuf);
        sta = SLE_Wait();
        if(sta)break;
        StartAdr++;								                  
        WriteBuf++;		
    }
    return 0;
}


//功    能：读加密存储器
//输	  入：unsigned char *Psw  --- 用于装读到的加密存储器内容,长度为4个字节
//		  Psw第一字节: 			 错误计数器值
//		  Psw第二字节到第四字节: 卡的密码值
//输	  出：0 --- 读成功
//		  1 --- 表示无效卡或者卡损坏
//注	  意: 必须校验密码正确才能读到正确的密钥值,否则读到的密码值为00 00 00
unsigned char SLE_RD_PSW(unsigned char* Psw)
{
    unsigned char i = 0;
    
    if(SLE_Rst() == 1)return 1;
    
    SLE_WR_Cmd(SLE_RD_PSCR, 0x00, 0x00);
    
    for(i = 0; i < 4; i++)
    {
        *Psw = SLE_RD_Byte();
        Psw ++;
    }
    return 0;
}

//功    能：校验密码,把Psw中1，2，3字节的内容分别与加密存储器的1，2，3字节比较
//输	  入：unsigned char *Psw  --- 待校验的密码值,长度为3个字节
//输    出:	        3: 核对密码成功
//					0: 卡已报废
//					1: 只剩一次校验机会,校验密码失败
//					2: 只剩二次校验机会,校验密码失败
//					4: 卡为无效卡或已损坏
unsigned char SLE_Check_PSW(unsigned char * psw)
{
    unsigned char ReadBuf[4];
    unsigned char k;
    
    if(SLE_RD_PSW(ReadBuf) == 1)return 4;
    
    printf("ReadBuf[0] = %h\r\n",ReadBuf[0]);
    if(ReadBuf[0] == 0x07)
    {
        SLE_WR_Cmd(SLE_WR_PSCR, 0x00, 0x33);//将EC写为0x03
        SLE_Wait();
        printf("Check 1\r\n");
    }
    else if (ReadBuf[0] == 0x06 || ReadBuf[0] == 0x05 || ReadBuf[0] == 0x03)
    {
        SLE_WR_Cmd(SLE_WR_PSCR, 0x00, 0x01);//将EC写为0x01
        SLE_Wait();
        printf("Check 2\r\n");
    }
    else if(ReadBuf[0] == 0x01 || ReadBuf[0] == 0x02 || ReadBuf[0] == 0x04)
    {
        SLE_WR_Cmd(SLE_WR_PSCR, 0x00, 0x00);//将EC写为0x00
        SLE_Wait();
        printf("Check 3\r\n");
    }
    
    SLE_WR_Cmd(SLE_PSC_CHK,0x01, psw[0]); //校验密码的第一个字节
    SLE_Wait();
    SLE_WR_Cmd(SLE_PSC_CHK,0x02, psw[1]); //校验密码的第二个字节
    SLE_Wait();
    SLE_WR_Cmd(SLE_PSC_CHK,0x03, psw[2]); //校验密码的第三个字节
    SLE_Wait();
    
    SLE_WR_Cmd(SLE_WR_PSCR, 0, 0x07);  //擦除错误计数器
    SLE_Wait();
    
    SLE_WR_Cmd(SLE_RD_PSCR, 0, 0);		//读加密存储器命令  
    //读加密存储器的四个字节
    for(k = 0; k < 4; k++)
    {
        printf("k = %d\r\n",k);
        
        ReadBuf[k] = SLE_RD_Byte();	
        
        printf("Readbuf[%d] = %x\r\n",k,ReadBuf[k]);
    }
    
    if(ReadBuf[0] == 0x07) return 3;	//剩下3次校验机会,校验密码成功
    else if(ReadBuf[0] == 0x06 || ReadBuf[0] == 0x05 || ReadBuf[0] == 0x03) return 2;//剩下2次校验机会,校验密码失败
    else if(ReadBuf[0] == 0x04 || ReadBuf[0] == 0x02 || ReadBuf[0] == 0x01) return 1;//剩下1次校验机会,校验密码失败
    else return 0;		//剩下0次校验机会,卡报废
    
}


//功    能：修改加密存储器中的密码
//输	  入：NewPsw -- 新密码缓冲区,长度为3个字节
//输	  出：0 --- 读成功
//		  1 --- 表示无效卡或者卡损坏
//注	  意: 必须校验密码成功后才能修改密码, 否则密码写不进卡中
unsigned char SLE_Set_PSW(unsigned char * psw)
{
    unsigned char i;
    
    if(SLE_Rst() == 1)return 1;
    
    for(i = 0; i < 3; i++)
    {
        SLE_WR_Cmd(SLE_WR_PSCR, i + 1, psw[i]);		//发送新的密码值
    }
    return 0;
}
/********************************End of File************************************/#include "SLE4442.h"



